/*
 * @Author: 奶龙也是龙 15104937352@163.com
 * @Date: 2025-06-27 10:17:25
 * @LastEditors: 奶龙也是龙 15104937352@163.com
 * @LastEditTime: 2025-06-29 11:18:51
 * @FilePath: \实训大二\Calculator.java
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import java.awt.Color;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

//继承JFrame 为了直接复用swing框架中窗口管理的能力
//为了子类可以直接调用JFrame public方法
//ApplicationListener 是Java中事件核心处理机制的核心部分
//为了建立计算机组件和用户操作之间的响应机制
public class Calculator extends JFrame implements ActionListener{
    private Timer timer;
    //声明界面组件
    //上下两个容器面板 文本框区域 按钮区域
    private JPanel north,center;
    //文本框 显示计算过程,结果或者日期时间
    private JTextField field;
    //按钮
    private JButton[] btns;
    //初始化窗口 -构造器 构造方法
    public Calculator(){
        //设置窗口标题
        setTitle("计算器");
        //设置窗口大小
        setSize(700,700);
        //设置窗口关闭时程序
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        //设置窗口位置
        setLocationRelativeTo(null);
        //初始化界面组件
        initComponent();
        //设置窗口显示
        setVisible(true);
    }
    
    //初始化界面组件
     private void initComponent(){
        Color NUM_COLOR = new Color(230, 230, 230); // 数字键浅灰色
        Color OP_COLOR = new Color(255, 165, 0);   // 运算符橙色
        Color lightBlue = new Color(135, 206, 235); //其他键颜色
        //创建面板容器
        //容器面板 文本区域
        north =new JPanel();
        //按钮区域
        center = new JPanel();
        //文本框 显示计算过程
        field = new JTextField();
        //设置输入框大小
        field.setPreferredSize(new Dimension(700,150));
        //禁止通过键盘输入编辑
        field.setEditable(false);
        //设置输入框字体和大小
        field.setFont(new Font("SansSerif",Font.BOLD,25));
        //按钮文本内容
        String [] str =new String[]{
            "7","8","9","+",
            "4","5","6","-",
            "1","2","3","×",
            "0",".","=","÷",
            "C","B","T","S"
        };
        //按钮数组
        btns = new JButton[str.length];
       for(int i=0;i < btns.length;i++){
        btns[i]=new JButton(str[i]);
        btns[i].setFont(new Font("SansSerif",Font.BOLD,25));
        if(str[i].matches("[0-9]")){ // 数字键（正则匹配 0-9）
        btns[i].setBackground(NUM_COLOR);
        btns[i].setForeground(Color.BLACK);
    } else if("+×-÷".contains(str[i])){ // 运算符
        btns[i].setBackground(OP_COLOR);
        btns[i].setForeground(Color.WHITE);
    } else{
        btns[i].setBackground(lightBlue);
        btns[i].setForeground(Color.WHITE);
    }
       }
       //
     
        // 将组件放到窗口中
        // 设置布局管理器
         // north 顶部面板 使用 BorderLayout 边界布局
        north.setLayout(new BorderLayout());
        
        // center 中间面板 使用5行四列网格布局
        center.setLayout(new GridLayout(5,4));
        // 组件设置
        // field 文本框 添加到 north 顶部面板 使用 BorderLayout 居中
        north.add(field,BorderLayout.CENTER);
        //btns 按钮 添加到center面板增强 for循环
       for (JButton btn :btns){
        //通过遍历将所有按钮添加到center面板
        center.add(btn);

       }

        // 将 north 顶部面板 添加到窗口中
        add(north,BorderLayout.NORTH);
        // 将 center 顶部面板 添加到窗口中
        add(center);
        //绑定按钮的监听事件
        for(JButton btn : btns){
            //this代表当前对象实例
            btn.addActionListener(this);
        }
        }
    //处理按键文本
    private void setBtnText(String text){
        switch (text) {
            
            case "C":
            //清空功能
                field.setText("");
                stopTimer();
               //System.out.println("C");
                break;
            case "B":
            //退格功能：
            //获取输入框的内容
                String numText = field.getText();
            //两种情况 可以通过isEmpty
                if(numText.length()!=0){
                    //输入框内容不为空
                    //numText的长度减一
                   String lastText = numText.substring(0,numText.length()-1);
                   //退格后的文本放到输入框
                   field.setText(lastText);
                }else{

                }
                System.out.println("B");
                break;
            case "T":
                startTimer();
                break;
            case "S":
            zidingyi();
                System.out.println("S：自定义功能");
                break;  
            case "=":
            Calculate();
            break; 
            case "0":
    String currentText1 = field.getText();
    if (currentText1.isEmpty()) {
        field.setText("0");  // 空输入时添加0
    } else {
        char lastChar = currentText1.charAt(currentText1.length() - 1);
        
        // 如果最后一个字符是运算符，直接添加0
        if (lastChar == '+' || lastChar == '-' || lastChar == '*' || lastChar == '/') {
            field.setText(currentText1 + "0");
            return;
        }
        
        // 使用正则表达式查找最后一个数字部分
        Matcher matcher = Pattern.compile("(\\d+(\\.\\d+)?)").matcher(currentText1);
        String lastNumber = "";
        //end() 方法返回当前找到的匹配子串在原字符串中的结束索引位置
        int lastNumberEnd = -1;
        
        while (matcher.find()) {
            //获取当前找到的匹配整个正则表达式模式的子串
            lastNumber = matcher.group();
            //返回当前找到的匹配子串在原字符串中的结束索引位置
            lastNumberEnd = matcher.end();
        }
        
        // 如果找到了数字部分，检查是否为前导零
        if (!lastNumber.isEmpty() && lastNumberEnd == currentText1.length()) {
            // 检查是否为前导零（整数部分以0开头且长度大于1）
            if (lastNumber.startsWith("0") && !lastNumber.contains(".") && lastNumber.length() > 0) {
                return;  // 禁止添加前导零
            }
        }
        
        // 其他情况正常添加0
        field.setText(currentText1 + "0");
    }
    return;
            case "1":
            case "2":
            case "3":
            case "4":
            case "5":
            case "6":
            case "7":
            case "8":
            case "9":
            //System.out.println("setBtnText:"+text);
            //按下数字键 把数字放到输入框中
            String oldText = field.getText();
            //如果输入框中有数字作拼接
            field.setText(oldText+text);
            break; 
            case "-":
            String twoText = field.getText();
            if (twoText.length() > 0 && !Character.isDigit(twoText.charAt(twoText.length() - 1))) {
             return;
              }
             field.setText(twoText + text);
             break;
            case "+":
            case "×":
            case "÷":
                String sixText = field.getText();
                if (sixText.length() == 0) {
                   return;
                }
                //charAt获取指定索引字符 方法， isDigit判断字符是否为数字方法 。
                if (sixText.length() > 0 && !Character.isDigit(sixText.charAt(sixText.length() - 1))) {
             return;
              }
             field.setText(sixText + text);
             break;
    case ".":
    String currentText = field.getText();
    if (currentText.isEmpty()) {
        field.setText("0.");
    } 
    else {
        char lastChar = currentText.charAt(currentText.length() - 1);
        // 只在加减乘除后补0，其他非数字字符不处理
        if (lastChar == '+' || lastChar == '-' || lastChar == '*' || lastChar == '/') {
            field.setText(currentText + "0.");
        } 
         else if(lastChar == '.'){
        return;
         }
        else {
            // 改进：使用正则表达式识别数字部分
            Matcher matcher = Pattern.compile("(\\d+(\\.\\d+)?)").matcher(currentText);
            String lastNumber = "";
            while (matcher.find()) {
                lastNumber = matcher.group();
            }
            // 如果找到数字部分，检查其是否已有小数点
            if (!lastNumber.isEmpty() && !lastNumber.contains(".")) {
                field.setText(currentText + ".");
            } 
            // 已有小数点则忽略输入
        }
    }
    return;
            }
        }
   private void zidingyi() {
    String input = JOptionPane.showInputDialog(this, "请输入闹钟时间 (HH:mm:ss)：");
    if (input != null && !input.isEmpty()) {
        try {
            LocalTime alarmTime = LocalTime.parse(input, DateTimeFormatter.ofPattern("HH:mm:ss"));
            LocalTime now = LocalTime.now();
            long delay = alarmTime.toNanoOfDay() - now.toNanoOfDay();
            if (delay < 0) {
                delay += 24 * 60 * 60 * 1_000_000_000L;
            }

            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                // 新增：保存 Clip 引用，用于停止音频
                private Clip clip;  

                @Override
                public void run() {
                    try {
                        File soundFile = new File("C:\\Users\\李伟\\Desktop\\实训大二\\naozhong.wav");
                        AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(soundFile);
                        AudioFormat format = audioInputStream.getFormat();
                        DataLine.Info info = new DataLine.Info(Clip.class, format);

                        if (AudioSystem.isLineSupported(info)) {
                            clip = (Clip) AudioSystem.getLine(info);
                            clip.open(audioInputStream);
                            clip.start();
                        } else {
                            SoundPlayer.fallbackToSystemBeep();
                        }

                        // 弹窗阻塞：用户点击“确定”后，继续执行关闭音频逻辑
                        JOptionPane.showMessageDialog(Calculator.this, "闹钟时间到！");

                        // 关闭音频（用户点确定后执行）
                        if (clip != null && clip.isRunning()) {
                            clip.stop();
                            clip.close();
                        }

                    } catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
                        System.err.println("播放音频失败: " + e.getMessage());
                        SoundPlayer.fallbackToSystemBeep();
                    }
                }
            }, delay / 1_000_000);

            field.setText("已设置闹钟：" + alarmTime);

        } catch (DateTimeParseException e) {
            JOptionPane.showMessageDialog(this, "时间格式错误，请使用 HH:mm:ss 格式。");
        }
    }
}

public static class SoundPlayer {
    public static void playWav(String filePath) {
        // 原播放逻辑不变（可保留，也可整合到 TimerTask 中，按需调整）
    }

    private static void fallbackToSystemBeep() {
        java.awt.Toolkit.getDefaultToolkit().beep();
    }
}
    private void Calculate(){
        //获取用户输入内容
        String expression = field.getText();
        //如果有×÷替换*/
        //执行计算操作 使用js引擎
        ScriptEngineManager manager = new ScriptEngineManager();
        //初始化计算引擎 使用javascript解析数学表达式
        ScriptEngine engine = manager.getEngineByName("javascript");
        //计算
        try {
           StringBuilder result = new StringBuilder();
            for(char c:expression.toCharArray()){
            if (c == '÷'){
                result.append('/');
            }
            else if (c == '×') {
                result.append('*');
            }else{
                result.append(c);
            }
        }
         String expression1 = result.toString();
         System.out.println(expression1);
            //try中放可能出现异常的代码
            Object result1 = engine.eval(expression1);
            field.setText(result1.toString());
        } catch (ScriptException e) {
            //catch中放异常的处理方式
            field.setText("运算错误");
            e.printStackTrace();
        }
        
    }
    //实现接口中的抽象方法 处理事件
    @Override
    public void actionPerformed(ActionEvent a){
        //此处可以捕获到ActionListener监听的事件
        //获取被点击按钮的文字
        Object source = a.getSource();
        if (source instanceof JButton){
            JButton btn = (JButton) source;
            String text = btn.getText();
            //System.out.println(text);
            setBtnText(text);
        }
    }
    private void startTimer() {

        
         timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            LocalTime currentTime = LocalTime.now();
            String time = "北京时间：";
            
            SwingUtilities.invokeLater(() -> {
                field.setText(time + currentTime.toString());
            });
        }
    }, 0, 1000); // 初始延迟 0ms，每 1000ms（1秒）执行一次
    }

    // 停止定时器
    private void stopTimer() {
         if (timer != null) {
        timer.cancel(); // 取消定时任务
        timer = null;   // 置空，避免重复操作
    }
}
    public static void main(String[] args) { 
        //System.out.println("hello,Calculator");
        //创建类的对象-线程不安全new Calculator();
       //是Java Swing 开发中确保线程安全的核心代码
        SwingUtilities.invokeLater(Calculator::new);
    }
}
